﻿using System;
using System.Reflection;
using System.Configuration;
using System.Globalization;
using System.Collections.Generic;
using System.Drawing;

using SBPweb.Localization;

using SBPweb.Modules.Smartparts;

namespace SBPweb.Modules.Modularity
{
    /// <summary>
    /// Base Class of Modules. It implements basic functionality of IModule
    /// </summary>
    public abstract class ModuleBase : IModule
    {
        #region Protected fields

		/// <summary>
		/// ServiceDictionary pGlobalServices
		/// </summary>
		private ServiceDictionary pGlobalServices;
		/// <summary>
		/// SessionDictionary pGlobalSession
		/// </summary>
		private SessionDictionary pGlobalSession;
		/// <summary>
		/// string pAsmPath
		/// </summary>
		private string pAsmPath;
		/// <summary>
        /// IModuleHost pHost
        /// </summary>
        protected IModuleHost pHost;
        /// <summary>
        /// ModuleHostType pHostType
        /// </summary>
        protected ModuleHostType pHostType;
        /// <summary>
        /// ResourceHandler pResources
        /// </summary>
        protected ResourceHandler pResources;
        /// <summary>
        /// string pName
        /// </summary>
        protected string pName;
        /// <summary>
        /// string pTypeName
        /// </summary>
		protected string pTypeName;
        /// <summary>
        /// bool pIsInitialized
        /// </summary>
        protected bool pIsInitialized = false;
        /// <summary>
        /// bool pIsVisible
        /// </summary>
        protected bool pIsVisible = false;
        /// <summary>
        /// bool pIsEnabled
        /// </summary>
        protected bool pIsEnabled = false;
        /// <summary>
        /// System.Version pVersion
        /// </summary>
        protected System.Version pVersion;
        /// <summary>
        /// System.Version pFileVersion
        /// </summary>
        protected System.Version pAsmVersion;
        /// <summary>
        /// Icon pIcon
        /// </summary>
        protected Icon pIcon;
        /// <summary>
        /// bool pAsyncLoad
        /// </summary>
		protected bool pAsyncLoad = false;
		/// <summary>
		/// bool pAllowUnload
		/// </summary>
        protected ApplicationSettingsBase pSettings;
		/// <summary>
		/// ModuleProfile pModuleProfile
		/// </summary>
		protected ModuleProfile pModuleProfile;
		/// <summary>
		/// IPersistable pParentPersistable
		/// </summary>
		protected IPersistable pParentPersistable;
		/// <summary>
		/// System.Configuration.Configuration pConfiguration
		/// </summary>
		protected System.Configuration.Configuration pConfiguration;

        #endregion

        #region Constructor logic

		/// <summary>
		/// Constructor of ModuleBase
		/// </summary>
		/// <param name="host"></param>
		public ModuleBase(IModuleHost host)
		{
			pHost = host;
			pParentPersistable = null;
			pHostType = host.HostType;
            pResources = new ResourceHandler(this.GetType(), new List<CultureInfo>(Host.SupportedCultures));

			Assembly asm = Assembly.GetAssembly(this.GetType());
            AssemblyName asmName = asm.GetName();
            string version = ResourceHandler.GetAssemblyCustomAttribute<AssemblyFileVersionAttribute>(asm) as string;

			pConfiguration = null;

			pVersion = new System.Version(version);
            pAsmVersion = asmName.Version;
			pGlobalServices = Host.ModuleLoader.Services;
			pGlobalSession = Host.ModuleLoader.Session;
			pAsyncLoad = false;
            pAsmPath = asm.Location;
            InitializeConfiguration(asm);
        }

        #endregion

        #region Property accessors

        /// <summary>
        /// ModuleHost instance
        /// </summary>
        public IModuleHost Host
        {
            get
            {
                return pHost;
            }
        }

        /// <summary>
        /// Type of the ModuleHost
        /// </summary>
        public ModuleHostType HostType
        {
            get
            {
                return pHostType;
            }
        }

        /// <summary>
        /// Services
        /// </summary>
        public ServiceDictionary Services
        {
            get
            {
                return pGlobalServices;
            }
            internal set
            {
                pGlobalServices = value;
            }
        }

		/// <summary>
		/// Session
		/// </summary>
		public SessionDictionary Session
		{
			get
			{
				return pGlobalSession;
			}
			internal set
			{
				pGlobalSession = value;
			}
		}

        /// <summary>
        /// Name of the Module it must be unique
        /// </summary>
        public string Name
        {
            get
            {
                return pName;
            }
            protected set
            {
                pName = value;
            }
        }

        /// <summary>
        /// Gets the full name of the Type of module
        /// </summary>
		public string TypeName
		{
			get
			{
				return pTypeName;
			}
			internal set
			{
				pTypeName = value;
			}
		}

        /// <summary>
        /// This flag is true when module is initialized
        /// </summary>
        public bool IsInitialized
        {
            get
            {
                return pIsInitialized;
            }
			protected set
			{
				pIsInitialized = value;
			}
        }

        /// <summary>
        /// Gets or sets the visibility of the module
        /// </summary>
        public virtual bool IsVisible
        {
            get
            {
                return pIsVisible;
            }
            set
            {
                foreach (ISmartpart sm in Smartparts)
                {
                    sm.IsVisible = value;
                }
                pIsVisible = value;
                if (VisibleChanged != null)
                {
                    VisibleChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets or sets the Enable flag for module
        /// </summary>
        public virtual bool IsEnabled
        {
            get
            {
                return pIsEnabled;
            }
            set
            {
                foreach (ISmartpart sm in Smartparts)
                {
                    sm.IsEnabled = value;
                }
                pIsEnabled = value;
                if (EnabledChanged != null)
                {
                    EnabledChanged(this, EventArgs.Empty);
                }
            }
        }

        /// <summary>
        /// Gets the ResourceHandler
        /// </summary>
        public ResourceHandler Resources
        {
            get
            {
                return pResources;
            }
        }

        /// <summary>
        /// Gets the Smartparts of the module
        /// </summary>
        public ISmartpart[] Smartparts
        {
            get
            {
                return Array.FindAll<ISmartpart>(pHost.Smartparts.Items, new Predicate<ISmartpart>(IsParentOf));
            }
        }

        /// <summary>
        /// Gets the Version of the module
        /// </summary>
        public System.Version Version
        {
            get
            {
                return pVersion;
            }
        }

        /// <summary>
        /// Gets the FileVersion of the module
        /// </summary>
        public System.Version AssemblyVersion
        {
            get
            {
                return pAsmVersion;
            }
        }

        /// <summary>
        /// Gets the Icon of the module
        /// </summary>
        public Icon Icon
        {
            get
            {
                return pIcon;
            }
        }

        /// <summary>
        /// Unique key of persistable. The Name property of the Module is used default.
        /// </summary>
		public string PersistencyKey
		{
			get
			{
				return pName;
			}
		}

        /// <summary>
        /// Gets the Configuration settings of the module
        /// </summary>
        public ApplicationSettingsBase Settings
        {
            get
            {
                return pSettings;
            }
        }

        /// <summary>
        /// Capability of asynchronous Loading and initializing
        /// </summary>
		public bool AsyncLoad
		{
			get
			{
				return pAsyncLoad;
			}
			protected set
			{
				pAsyncLoad = value;
			}
		}

		/// <summary>
		/// The parent IPersistable object of module
		/// </summary>
		public IPersistable ParentPersistable
		{
			get
			{
				return pParentPersistable;
			}
			set
			{
				pParentPersistable = value;
			}
		}

		/// <summary>
		/// Returns the module's configuration file as System.Configuration.Configuration
		/// </summary>
		public System.Configuration.Configuration Configuration
		{
			get
			{
				if (pConfiguration == null)
				{
					string privatepath = System.Reflection.Assembly.GetAssembly(this.GetType()).Location;
					pConfiguration = System.Configuration.ConfigurationManager.OpenExeConfiguration(privatepath);
				}
				return pConfiguration;
			}
		}

        #endregion

        #region Public events

        /// <summary>
        /// VisibleChanged
        /// </summary>
        public event EventHandler VisibleChanged;
        /// <summary>
        /// EnabledChanged
        /// </summary>
        public event EventHandler EnabledChanged;

        #endregion

        #region Public methods

        /// <summary>
        /// Initialzes the module this method called by the ModuleLoader
        /// </summary>
		public abstract void Initialize();

        /// <summary>
        /// Terminatese the module this method called by the ModuleLoader
        /// </summary>
		public abstract void Terminate();

        /// <summary>
        /// Base pattern method of state saving
        /// </summary>
		public abstract void SavePersistency();

        /// <summary>
        /// Base pattern method of state loading
        /// </summary>
		public abstract void LoadPersistency();

		/// <summary>
		/// Returns true, if the module is the parent of the passed smartpart
		/// </summary>
		/// <param name="smartpart">ISmartpart smartpart</param>
		/// <returns>bool</returns>
		public bool IsParentOf(ISmartpart smartpart)
		{
			return smartpart.ParentModule == this;
		}

		/// <summary>
		/// Disposes the module
		/// </summary>
		public virtual void Dispose()
		{
			pHost = null;
			pResources = null;
			pVersion = null;
			if (pIcon != null)
			{
				pIcon.Dispose();
				pIcon = null;
			}
		}

        #endregion

        #region Private helper methods

        private void InitializeConfiguration(Assembly asm)
        {
            try
            {
                Configuration conf = ConfigurationManager.OpenExeConfiguration(pAsmPath);
				pModuleProfile = (ModuleProfile)conf.Sections.Get("moduleProfile");
				
				ConfigurationSectionGroup csg = conf.GetSectionGroup("applicationSettings");
				if (csg != null)
				{
					ConfigurationSection settingsSection = GetPropertiesSection(csg.Sections);
					pSettings = (ApplicationSettingsBase)asm.CreateInstance(settingsSection.SectionInformation.Name);
				}
				else
				{
					pSettings = null;
				}
            }
            catch (Exception ex)
            {
				pHost.LogManager.WriteError(string.Format("Exception while initializing configuration - {0}", ex.ToString()), this, "ModuleLoader");
            }
        }

		private ConfigurationSection GetPropertiesSection(ConfigurationSectionCollection csc)
		{
			foreach (ConfigurationSection cs in csc)
			{
				if ((cs.ElementInformation.Type == typeof(ClientSettingsSection)) && cs.SectionInformation.Name.EndsWith("Properties.Settings"))
				{
					return cs;
				}
			}

			return null;
		}

        #endregion
	}
}
